package com.example.controller;

import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 浏览器不会自动帮你保存 token，保存和使用 token 的操作是由前端代码手动完成的。
 * Cookie 是浏览器管理的；Token 是前端程序员管理的。
 * 类型	                    浏览器行为	                是否自动保存
 * Set-Cookie	            浏览器自动接收、存储 cookie	    ✅ 是
 * { token: xxx } JSON 返回	浏览器不会做任何处理	        ❌ 否
 * <p>
 * 为什么不让浏览器自动保存 Token？
 * 因为 Token：
 * 通常不是用 Cookie 的形式返回，而是放在 JSON 响应里
 * 前端需要控制 Token 的保存方式（localStorage？sessionStorage？cookie？）
 * 前端还要决定：什么时候使用、是否刷新、是否删除、是否传给其他服务
 */
@RestController
@RequestMapping("/Token")
@CrossOrigin(origins = "*")  // ✅ 允许所有域跨域访问
public class TokenController {

    /**
     * 用一个 Map 来模拟 Token 的保存机制（实际项目中会用 Redis 或数据库来存储）。
     * 模拟 token 存储：token -> username
     */
    private final Map<String, String> tokenStore = new HashMap<>();

    /**
     * 登录，返回一个 token
     * 步骤	            谁来处理	    说明
     * 生成 Token	    后端	        登录成功后生成并返回 JSON
     * 提取并保存 Token	✅ 前端处理	前端通过 JS 提取 token 并保存
     * 带上 Token 请求	✅ 前端处理	通过请求头传给后端
     * 验证 Token	    后端	        后端从请求头中解析 token 并验证合法性
     * 前端发起登录请求（用户名+密码）
     * ↓
     * 后端验证成功 → 生成 token → 通过 JSON 返回给前端
     * ↓
     * 前端拿到 token → 存储在浏览器本地（localStorage / sessionStorage / cookie）
     * ↓
     * 后续请求时 → 前端带上 token（通常放在请求头 Authorization）
     */
    @GetMapping("/login")
    public Map<String, String> login(@RequestParam String username, @RequestParam String password) {
        Map<String, String> response = new HashMap<>();
        /**
         * 模拟用户名密码验证（在实际中需要查数据库）
         */
        if ("admin".equals(username) && "123456".equals(password)) {
            /**
             * 生成唯一 token
             */
            String token = UUID.randomUUID().toString();
            /**
             * 保存到 token 存储中
             */
            tokenStore.put(token, username);
            response.put("token", token);
            response.put("msg", "登陆成功");
        } else {
            response.put("msg", "用户名或密码错误");
        }
        return response;
    }

    /**
     * 根据 token 获取用户信息
     * Token 的保存是由前端页面的代码“主动告诉浏览器怎么保存”的，浏览器本身不会自动保存 Token。
     * ✔️ Cookie 和 Session 都可以由浏览器自动保存（前端不管也能用）
     * ❌ Token 必须由前端显式代码保存，浏览器不会自动保存它
     */
    /**
     * 问题核心原因
     * 确实将 token 保存在了 localStorage 中，但在后续请求中没有正确携带它到后端。
     * 后端要求 Authorization 请求头，但你的前端代码没有主动设置这个请求头，导致 MissingRequestHeaderException。
     * 浏览器的 开发者工具（F12） 可以查看 localStorage 中的 token（在 Application → Local Storage 下），但默认不会自动在请求头中添加 Authorization。
     */
    /**
     * Token 的存储 vs. 发送
     * 步骤	            操作	                                            你的代码情况
     * 1. Token 存储	    登录后，前端将 token 存入 localStorage	            ✅ 你的代码已实现：localStorage.setItem("auth_token", data.token)
     * 2. Token 发送	    后续请求需手动将 token 放入 Authorization 请求头	    ❌ 你的代码未实现，导致请求头缺失
     * 3. 如何验证 Token 是否被携带？
     * 在浏览器开发者工具的 Network 选项卡中：
     * 点击请求 /info。
     * 检查 Request Headers 部分是否包含：
     * Authorization: <你的token>
     * 如果没有，说明前端未正确发送 token。
     */
    @GetMapping("/info")
    public Map<String, String> getUserInfo(@RequestHeader("Authorization") String token) {
        Map<String, String> response = new HashMap<>();
        String user = tokenStore.get(token);
        if (user != null) {
            response.put("user", user);
            response.put("msg", "验证成功");
        } else {
            response.put("msg", "无效的 Token");
        }
        return response;
    }

    /**
     * 注销 token（移除）
     * Token（如 JWT 或 UUID Token）是无状态的字符串，它的认证流程完全依赖 前端主动存储和发送，而 浏览器不会自动处理 Token（不像 Cookie 会被浏览器自动管理）。
     * 场景复现
     * 通过前端页面访问：
     * 用户登录后，前端将 Token 保存到 localStorage。
     * 后续请求中，前端代码 手动添加 Authorization: Bearer <token> 请求头。
     * 后端校验 Token 并返回数据。
     * 直接访问后端接口（如浏览器地址栏输入URL）：
     * 没有 Token：浏览器地址栏输入 URL 或直接访问 API 时，不会自动携带 Authorization 头。
     * 后端返回 401：因为请求头缺失，认证失败。
     * 根本原因
     * Token 需要前端代码显式传递，而直接访问 API 时：
     * 没有执行前端代码（如 fetch 或 axios），无法添加 Authorization 头。
     * 浏览器不会像处理 Cookie 一样自动存储和发送 Token。
     */
    @GetMapping("/logout")
    public Map<String, String> logout(@RequestHeader("Authorization") String token) {
        Map<String, String> response = new HashMap<>();
        if (tokenStore.containsKey(token)) {
            tokenStore.remove(token);
            response.put("msg", "已注销");
        } else {
            response.put("msg", "Token 无效或已过期");
        }
        return response;
    }

}
/**
 * Token 确实用于验证用户是否存在，但比验证码更强大（携带用户信息、权限等）。
 * Token 有明确的生命周期，过期后：
 * 后端会拒绝请求
 * 前端需引导用户重新登录
 * Token 不是「被动验证」，而是：
 * 状态化方案：后端主动查表确认
 * 无状态方案：通过密码学签名自验证
 */
